﻿using KInterfaces;
using KXmlUIControl;
using LogLib;
using Microsoft.Ink;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace KFormBase
{
    /// <summary>
    /// 模块页面
    /// </summary>    
    public class ModulePage : IDisposable
    {
        #region static Fields and Function
        private static string RootDirectory = "";
        static ModulePage()
        {
            string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
            directory = directory.Substring(6);
            DirectoryInfo dllDirectory = new DirectoryInfo(directory);
            RootDirectory = dllDirectory.FullName + @"\Module";
        }
        #endregion

        /// <summary>
        /// 页面配置对象
        /// </summary>
        private XmlPageObject _config = null;
        public XmlPageObject Config
        {
            get { return _config; }
        }

        private XmlConfigForm _pageConfig = null;

        /// <summary>
        /// 最新错误信息
        /// </summary>
        public string Error { get; private set; }

        /// <summary>
        /// 模块在应用程序中的唯一标识Id
        /// </summary>       
        public string SID { get; private set; }

        /// <summary>
        /// 模块页面在列表中的位置
        /// </summary>       
        public int Pos { get; private set; }

        /// <summary>
        /// 主页面流程业务的实例（全面处理窗体业务对象）
        /// </summary>
        public IPageProcess MainPageProcess { get; private set; }

        /// <summary>
        /// 子页面流程业务的实例（全面处理窗体业务对象）
        /// </summary>
        public IPageProcess ChildPageProcess { get; private set; }

        /// <summary>
        /// 模块主页面窗体的实例（被包裹在模块页面窗体中）
        /// </summary>
        public UserControl MainPage { get; private set; }

        /// <summary>
        /// 模块子页面窗体的实例（被包裹在模块页面窗体中）
        /// </summary>
        public UserControl ChildPage { get; private set; }

        /// <summary>
        /// 定义了页面窗体类型的程序集
        /// </summary>
        private Assembly _assembly = null;
        public Assembly PageAssembly
        {
            get { return _assembly; }
        }

        /// <summary>
        /// 主页面的指定类型
        /// </summary>   
        public Type MainPageType { get; private set; }

        /// <summary>
        /// 子页面的指定类型
        /// </summary>   
        public Type ChildPageType { get; private set; }

        /// <summary>
        /// 动态库文件的完整路径
        /// </summary>     
        public string FullFileName { get; private set; } = "";

        public bool Available
        {
            get
            {
                return _assembly != null && MainPageType != null;
            }
        }

        public bool Disposed { get; private set; } = false;

        public ModulePage(XmlPageObject config, int index)
        {
            _config = config;
            Pos = index;
            SID = Guid.NewGuid().ToString();         
        }

        public bool Initialize()
        {
            return LoadPageType();
        }

        /// <summary>
        /// 将主窗体的Process传递给子窗体
        /// </summary>
        //private void TransferProcessFromMainToChild()
        //{            
        //    MethodInfo setProcessMethod = ChildPageType.GetMethod("SetProcessBase");
        //    if(setProcessMethod != null && ChildPage != null)
        //    {
        //        setProcessMethod.Invoke(ChildPage, new object[] { MainPageProcess });
        //    }         
        //}

        /// <summary>
        /// 获取给定路径的完整绝对路径
        /// </summary>
        /// <param name="FilePath"></param>
        /// <returns></returns>
        private bool GetFullFilePath()
        {
            FullFileName = Path.Combine(RootDirectory, _config.Directory, _config.FileName);
            if (!File.Exists(FullFileName))
            {
                Error = $"加载类型{_config.TypeName}的动态库失败, 指定的文件{FullFileName}不存在: ";
                Log.WriteAsync(Error);
                return false;
            }
            return true;
        }

        private bool LoadPageType()
        {
            Error = "";
            if (!GetFullFilePath())
            {
                return false;
            }
            if (string.IsNullOrEmpty(_config.TypeName))
            {
                Error = _config.TypeName + "创建模块页面失败: 模块页面类型名称为空";
                Log.WriteAsync(Error);
                return false;
            }
            try
            {
                _assembly = Assembly.LoadFile(FullFileName);
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
                Error = $"模块页面{_config.TypeName}的类型加载失败, 无法加载指定的程序集: {FullFileName}\n 详情:{ex.Message}";
                Log.WriteAsync(Error);
                return false;
            }
            if (_assembly == null)
            {
                Error = _config.TypeName + "模块页面类型加载失败, 指定的程序集为空.";
                Log.WriteAsync(Error);
                return false;
            }
            try
            {
                MainPageType = _assembly.GetType(_config.TypeName);
                if(!string.IsNullOrEmpty(_config.ChildTypeName))
                {
                    ChildPageType = _assembly.GetType(_config.ChildTypeName);
                }               
                return true;
            }
            catch (Exception ex)
            {
                Error = $"模块页面类型{_config.TypeName}/{_config.ChildTypeName}加载失败, 异常详情: " + ex.Message;
                Log.WriteException(ex.ToString());
                return false;
            }
        }

        public XmlConfigForm LoadPageConfig(string languageCode, bool isMainPage)
        {
            XmlConfigForm pageConfig = null;
            string XmlConfigFolder = string.Format(@"{0}\{1}\UI\{2}\", RootDirectory, _config.Directory, languageCode);
            string XmlConfigFile = string.Format(@"{0}{1}.xml", XmlConfigFolder, this.MainPageType.Name);
            if (!File.Exists(XmlConfigFile))
            {
                Error = $"不存在的配置文件:{XmlConfigFile}";
                Log.WriteAsync(Error);
                throw new Exception(Error);
            }
            XmlPageReader reader = new XmlPageReader(XmlConfigFile);
            if (reader.TryLoadFormConfig(isMainPage, out pageConfig))
            {
                return pageConfig;
            }
            else
            {
                Error = reader.Error;
                Log.WriteAsync(Error);
                throw new Exception(Error);
            }
        }

        /// <summary>
        /// 利用反射从页面实例获取页面业务控制对象
        /// </summary>
        private IPageProcess GetPageProcess(Type type, object t, string pName)
        {
            IPageProcess pageProcess = null;
            PropertyInfo pInfo = type.GetProperty(pName, BindingFlags.Instance | BindingFlags.Public);
            if (pInfo != null)
            {
                object oVal = pInfo.GetValue(t, null);
                if (oVal != null)
                {
                    pageProcess = (IPageProcess)oVal;
                    if (pageProcess != null)
                    {
                        pageProcess.ID = _config.ID;
                        pageProcess.PageName = _config.TypeName;
                        pageProcess.ChineseName = _config.ChineseName;
                        Log.WriteAsync(_config.TypeName + "获取页面业务对象成功.");
                        return pageProcess;
                    }
                }
            }
            Error = $"获取页面{_config.TypeName}的业务对象失败.";
            Log.WriteAsync(Error);
            throw new Exception(Error);
        }

        private bool SetPagePropertyValue(Type type, UserControl page, string pName, object value)
        {
            PropertyInfo pInfo = type.GetProperty(pName, BindingFlags.Instance | BindingFlags.Public);
            if (pInfo != null)
            {
                pInfo.SetValue(page, value);
                return true;
            }
            else
            {
                Log.WriteAsync($"更新设置页面{_config.TypeName}的属性{pName}失败.");
                return false;
            }
        }

        private void CreateMainPage(string languageCode)
        {
            if (_assembly == null || MainPageType == null)
            {
                return;
            }
            XmlConfigForm pageConfig = LoadPageConfig(languageCode, true);
            object instance = null;
            try
            {
                instance = Activator.CreateInstance(MainPageType);
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
                Error = _config.TypeName + "创建页面类型为空: " + ex.Message;
                Log.WriteAsync(Error);
                throw new Exception(Error);
            }
            MainPage = instance as UserControl;
            if (MainPage != null)
            {
                MainPageProcess = GetPageProcess(MainPageType, MainPage, "Process");              
                SetPagePropertyValue(MainPageType, MainPage, "LanguageCode", languageCode);
                SetPagePropertyValue(MainPageType, MainPage, "UIConfig", pageConfig);
                MainPageProcess.InitCtrl(0);
            }
        }

        private void CreateChildPage(string languageCode)
        {
            if (_assembly == null || ChildPageType == null)
            {
                return;
            }
            XmlConfigForm pageConfig = LoadPageConfig(languageCode, false);
            object instance = null;
            try
            {
                instance = Activator.CreateInstance(ChildPageType);
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
                Error = _config.TypeName + "创建页面类型为空: " + ex.Message;
                Log.WriteAsync(Error);
                throw new Exception(Error);
            }
            ChildPage = instance as UserControl;
            if (ChildPage != null)
            {               
                //LanguageCode
                ChildPageProcess = GetPageProcess(ChildPageType, ChildPage, "Process");
                      
                SetPagePropertyValue(ChildPageType, ChildPage, "LanguageCode", languageCode);
                SetPagePropertyValue(ChildPageType, ChildPage, "UIConfig", pageConfig);
                ChildPageProcess.InitCtrl(1);
                BindingCtrlDataSource();
            }
        }

        //绑定控件数据源
        private void BindingCtrlDataSource()
        {
            foreach(Control childCtrl in ChildPage.Controls)
            {
                
                var mainCtrl = MainPage.Controls[childCtrl.Name];
                if (mainCtrl != null)
                {
                    
                    Type type = mainCtrl.GetType();
                    switch (type.Name)
                    {
                        case "TextBox":
                            Binding textBinding1 = new Binding("Text", mainCtrl, "Text", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(textBinding1);
                            Binding textBinding2 = new Binding("Visible", mainCtrl, "Visible", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(textBinding2);
                            break;
                        case "CheckBox":
                        case "KCheckBox":
                            Binding checkBinding1 = new Binding("Checked", mainCtrl, "Checked", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(checkBinding1);
                            Binding checkBinding2 = new Binding("Visible", mainCtrl, "Visible", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(checkBinding2);
                            break;
                        case "PictureBox":
                            //只有BackgroundImage绑定才有效
                            Binding pbxBinding1 = new Binding("BackgroundImage", mainCtrl, "BackgroundImage", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(pbxBinding1);

                            Binding pbxBinding2 = new Binding("Visible", mainCtrl, "Visible", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(pbxBinding2);
                            break;
                        case "InkPicture":
                            // 当在inkPicture1上进行手写时，将手写的墨迹复制到inkPicture2
                            //((Microsoft.Ink.InkPicture)mainCtrl).InkChanged += (s, e) =>
                            // 当在inkPicture1上进行手写时，将手写的墨迹复制到inkPicture2
                            var childInkPbx = (Microsoft.Ink.InkPicture)childCtrl;
                            var mainInkPbx = (Microsoft.Ink.InkPicture)mainCtrl;

                            // 当在childInkPbx上进行手写时，将手写的墨迹复制到mainInkPbx
                            childInkPbx.Stroke += (s, e) =>
                            {
                                // 创建一个和mainInkPbx同样大小的Bitmap，并将mainInkPbx的墨迹渲染到Bitmap中
                                Bitmap bitmap = new Bitmap(mainInkPbx.Width, mainInkPbx.Height);
                                using (Graphics g = Graphics.FromImage(bitmap))
                                {
                                    if (mainInkPbx.Image != null)
                                    {
                                        mainInkPbx.Image.Dispose();
                                        mainInkPbx.Image = null;
                                    }
                                    mainInkPbx.Renderer.Draw(g, childInkPbx.Ink.Strokes);
                                    // 将Bitmap设置为mainInkPbx的Image
                                    mainInkPbx.Image = bitmap;
                                }

                                
                            };

                            childInkPbx.Ink.InkDeleted += (s, e) =>
                            {
                                Bitmap bitmap = new Bitmap(mainInkPbx.Width, mainInkPbx.Height);
                                using (Graphics g = Graphics.FromImage(bitmap))
                                {
                                    if (mainInkPbx.Image != null)
                                    {
                                        mainInkPbx.Image.Dispose();
                                        mainInkPbx.Image = null;
                                    }
                                    mainInkPbx.Renderer.Draw(g, childInkPbx.Ink.Strokes);
                                    // 将Bitmap设置为mainInkPbx的Image
                                    mainInkPbx.Image = bitmap;
                                }                                
                            };

                            break;
                        case "Label":
                            Binding lblBinding2 = new Binding("Visible", mainCtrl, "Visible", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(lblBinding2);
                            break;
                        case "Button":
                            Binding btnBinding2 = new Binding("Visible", mainCtrl, "Visible", true, DataSourceUpdateMode.OnPropertyChanged);
                            childCtrl.DataBindings.Add(btnBinding2);
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        /// <summary>
        /// 利用反射创建指定模块页面类型的实例
        /// </summary>
        /// <param name="LanguageCode"></param>
        /// <returns></returns>
        public UserControl CreatOrGetMainPageInstance(string language)
        {
            if (MainPage == null)
            {
                CreateMainPage(language);
            }
            return MainPage;
        }

        /// <summary>
        /// 利用反射创建指定模块页面类型的实例
        /// </summary>
        /// <param name="LanguageCode"></param>
        /// <returns></returns>
        public UserControl CreatOrGetChildPageInstance(string language)
        {
            if (ChildPage == null)
            {
                CreateChildPage(language);
            }
            return ChildPage;
        }

        /// <summary>
        /// 应用指定的语言
        /// </summary>
        /// <param name="LanguageCode"></param>
        /// <returns></returns>
        public void ApplyLanguage(string LanguageCode)
        {
            if (_assembly == null || MainPageType == null)
            {
                return;
            }
            XmlConfigForm mainConfig = LoadPageConfig(LanguageCode, true);
            SetPagePropertyValue(MainPageType, MainPage, "UIConfig", mainConfig);          
            if (MainPageProcess != null)
            {
                MainPageProcess.ApplyLanguage(LanguageCode);
            }
            XmlConfigForm childConfig = LoadPageConfig(LanguageCode, false);
            SetPagePropertyValue(ChildPageType, ChildPage, "UIConfig", childConfig);
            if (ChildPageProcess != null)
            {
                ChildPageProcess.ApplyLanguage(LanguageCode);
            }
            //1、使用窗体自带资源切换语言
            //try
            //{
            //    ComponentResourceManager resources = new ComponentResourceManager(DefaultControl.GetType());
            //    List<Control> ltControls = new List<Control>();
            //    GetChildControls(ltControls, DefaultControl);
            //    DefaultControl.Text = resources.GetString("$this.Text");
            //    foreach (Control ctl in ltControls)
            //    {
            //        resources.ApplyResources(ctl, ctl.Name);
            //    }
            //}
            //catch (Exception ex)
            //{
            //}       
            //return "";
        }

        /// <summary>
        /// 把可以本地化的控件放入LIST
        /// </summary>
        /// <param name="ltControls"></param>
        /// <param name="ctl"></param>
        private void GetChildControls(List<Control> ltControls, Control ctl)
        {
            //容器不可以本地化
            if (!(ctl is ContainerControl))
            {
                ltControls.Add(ctl);
            }
            if (!ctl.HasChildren)
            {
                return;
            }
            foreach (Control c in ctl.Controls)
            {
                if (!(c is Form))
                {
                    GetChildControls(ltControls, c);
                }
            }
        }

        /// <summary>
        /// 退出所有业务流程，销毁窗体元素
        /// </summary>
        public void Dispose()
        {
            try
            {
                if (MainPageProcess != null)
                {
                    MainPageProcess.Exit();
                }
                if (ChildPageProcess != null)
                {
                    ChildPageProcess.Exit();
                }
                //if (MainPage != null)
                //{
                //    MainPage.Dispose();
                //}
                //if (ChildPage != null)
                //{
                //    ChildPage.Dispose();
                //}
                Disposed = true;
            }
            catch
            {
            }
        }

        public void Stop()
        {
            if(MainPageProcess != null)
            {               
                MainPageProcess.StopWork();
                MainPageProcess.ClearData();
                Log.WriteAsync($"页面{this.MainPageType.Name}结束工作.");
            }
        }

        public void Start(ModuleApplication currentApp)
        {
            if (MainPageProcess == null)
            {
                return;
            }
            MainPageProcess.SD = currentApp.SharedData;
            MainPageProcess.Job = currentApp.CurrentJob;
            RegisterEventsToPageProcess(currentApp);
            MainPageProcess.InitData();
            MainPageProcess.PlayWelcomeVoice();
            MainPageProcess.StartWork();
            Log.WriteAsync($"页面{this.MainPageType.Name}开始工作.");
        }

        private void RegisterEventsToPageProcess(ModuleApplication currentApp)
        {
            MainPageProcess.RemoveEvents();
            MainPageProcess.ModuleSwitched += currentApp.OnModuleSwitched;
            MainPageProcess.ModuleChanged += currentApp.OnModuleChanged;
            MainPageProcess.PageChanged += currentApp.OnPageChanged;
            MainPageProcess.PageSwitched += currentApp.OnPageSwitched;
            MainPageProcess.TakeAdminAction += currentApp.TakeAdministratorAction;
            MainPageProcess.LanguageChanged += currentApp.OnLanguageChanged;
            //MainPageProcess.RequestMsgSent += OnClientRequestSent;
        }
    }
}
